/**
 * 
 */
package travibot.meta.dao.jdbctemplate;

import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.sql.DataSource;

import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

import travibot.engine.MaterialFactory;
import travibot.meta.StructureType;
import travibot.meta.dao.MaterialTypeDAO;
import travibot.meta.dao.StructureTypeDAO;
import travibot.model.Cost;
import travibot.model.Material;
import travibot.utility.DescriptionNotFoundException;
import travibot.utility.LocaleSelector;

/**
 * @author Petr Macek
 * 
 */
public class StructureTypeDAOJdbcTemplate implements StructureTypeDAO {

    private static final String TABLE_TYPE = "STRUCTURE_TYPE";

    private static final String TABLE_NAME = "STRUCTURE_NAME";

    private static final String TABLE_TEXT = "TEXT";
    
    private static final String TABLE_COST = "COST";
    
    private static final String TABLE_STRUCTURE_COSTS = "STRUCTURE_COSTS";

    private JdbcTemplate jdbcTemplate;

    private LocaleSelector localeSelector;
    
    private MaterialTypeDAO materialDao;
    
    private MaterialFactory materialFactory;
    
    private StructureCostsResultSetExtractor costsResultSetExtractor;
    
    private StructureTypeRowMapper structureTypeMapper;

    public void setDataSource(DataSource dataSource) {

        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }    

    /*
     * (non-Javadoc)
     * 
     * @see travibot.meta.dao.BuildingTypeDAO#deleteBuildingType(travibot.meta.BuildingType)
     */
    public void deleteStructureType(StructureType type) {

        // TODO Auto-generated method stub

    }

    /*
     * (non-Javadoc)
     * 
     * @see travibot.meta.dao.BuildingTypeDAO#getBuildingType(java.lang.String)
     */
    public StructureType getStructureType(String title) throws DescriptionNotFoundException {

        StructureType result;
        try {
            String locale = localeSelector.getLocale().toString();
            StringBuffer sb = new StringBuffer();
            sb.append("select type.id_type, TEXT.text, type.class, type.max_level_main, type.max_level_other, type.ID_MATERIAL from ");
            sb.append("STRUCTURE_NAME as structure ");
            sb.append(" inner join " + TABLE_TYPE + " as type ON structure.ID_TYPE = type.ID_TYPE ");
            sb.append(" inner join LOCALE ON structure.ID_LOCALE = LOCALE.ID_LOCALE ");
            sb.append(" inner join TEXT ON structure.ID_TEXT = TEXT.ID_TEXT ");
            sb.append("where (LOCALE.ID_LOCALE = ? and TEXT.text = ?)");
            result = (StructureType)jdbcTemplate.queryForObject(sb.toString(), new Object[] { locale, title }, structureTypeMapper);
            
            
            sb = new StringBuffer();
            sb.append("select id_material, material_count, level from COST ");
            sb.append("inner join STRUCTURE_COSTS as sc on cost.id_cost = sc.id_cost ");
            sb.append("where ID_STRUCTURE_TYPE = ? ");
            sb.append("order by level");
            Map<Integer, Cost> costs = (Map<Integer, Cost>)jdbcTemplate.query(sb.toString(),new Object[] {result.getId()}, costsResultSetExtractor);
            if(costs != null){
                Set<Integer> keys = costs.keySet();
                for(int key: keys){
                    result.addCost(key, costs.get(key));
                }
            }            
        }
        catch (EmptyResultDataAccessException e) {
            throw new DescriptionNotFoundException(e);
        }
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see travibot.meta.dao.BuildingTypeDAO#setBuildingType(travibot.meta.BuildingType)
     */
    public void insertStructureType(StructureType type) {

        String sql;
        if (type.getMaterial() != null) {
            sql = "insert into " + TABLE_TYPE
                    + " (class, max_level_main, max_level_other, ID_MATERIAL) values (?, ?, ?, ?)";
            jdbcTemplate.update(sql, new Object[] { type.getImplementingClassName(), type.getMaxLevel(true),
                    type.getMaxLevel(false), type.getMaterial().getId() });
        }
        else {
            sql = "insert into " + TABLE_TYPE + " (class, max_level_main, max_level_other) values (?, ?, ?)";
            jdbcTemplate.update(sql, new Object[] { type.getImplementingClassName(), type.getMaxLevel(true),
                    type.getMaxLevel(false) });
        }
        sql = "select max(id_type) from " + TABLE_TYPE;
        type.setId(jdbcTemplate.queryForInt(sql));

        sql = "insert into " + TABLE_TEXT + " (text) values (?)";
        jdbcTemplate.update(sql, new Object[] { type.getName() });
        sql = "select max(id_text) from " + TABLE_TEXT;
        int idText = jdbcTemplate.queryForInt(sql);

        sql = "insert into " + TABLE_NAME + " (ID_TEXT, ID_LOCALE, ID_TYPE) values (?, ?, ?)";
        jdbcTemplate.update(sql, new Object[] { idText, localeSelector.getLocale().toString(), type.getId() });
        
        for(int level = 1; level <= type.getMaxAvailableLevel(); level++){
            
            List<Material> materials = materialFactory.getMaterials();
            for(Material currentMaterial : materials){
                try {
                    // vezmu jeho cost
                    int materialCost = type.getCost(level).getCost(currentMaterial);
            
                    //ulozim cost a material ID - neprojde, nemam cas, koukni na to. diky
                    sql = "insert into " + TABLE_COST + " (ID_MATERIAL, material_count) values (?,?)";
                    jdbcTemplate.update(sql, new Object[] { currentMaterial.getId(), materialCost });
                    sql = "select max(id_cost) from " + TABLE_COST;
                    int idCost = jdbcTemplate.queryForInt(sql);
                
                    //ulozim zaznam do vazebni tabulky
                    sql = "insert into " + TABLE_STRUCTURE_COSTS + " (ID_COST, ID_STRUCTURE_TYPE, LEVEL) values (?,?,?)";
                    jdbcTemplate.update(sql, new Object[]{ idCost, type.getId(), level});
                   
                    
                } catch (NullPointerException e){
                    continue;
                }
            }
        }      

    }

    public void setLocaleSelector(LocaleSelector localeSelector) {

        this.localeSelector = localeSelector;
    }

    
    public void setMaterialDao(MaterialTypeDAO materialDao) {
    
        this.materialDao = materialDao;
    }

    
    public void setMaterialFactory(MaterialFactory materialFactory) {
    
        this.materialFactory = materialFactory;
    }

    
    public void setCostsResultSetExtractor(StructureCostsResultSetExtractor costsResultSetExtractor) {
    
        this.costsResultSetExtractor = costsResultSetExtractor;
    }

    
    public void setStructureTypeMapper(StructureTypeRowMapper structureTypeMapper) {
    
        this.structureTypeMapper = structureTypeMapper;
    }
    
    
    
    
    
    
    
    

}
